using System;
using System.Xml;
using System.Drawing;
using System.Windows.Forms;
using System.Globalization;
using System.Security.Permissions;
using System.Reflection;
using needle.UI.Controls.Flat.Utilities.Drawing;
using needle.UI.Controls.Flat.Windows.Docking;
using needle.UI.Controls.Flat.Windows.Forms.Collections;
using needle.UI.Controls.Flat.Windows.Forms.Helpers;
using needle.UI.Controls.Flat.Resources;
using needle.UI.Controls.Flat.Resources.Keys;

namespace needle.UI.Controls.Flat.Windows.Docking
{
    public class Restore
    {
		protected Restore mchild;

		#region Constructors

		public Restore()
		{
			mchild = null;
		}

		public Restore(Restore child)
		{
			mchild = child;
		}

		#endregion

		#region Virtuals

		public virtual void PerformRestore(DockingManager dm) {}
		public virtual void PerformRestore(Window w) {}
        public virtual void PerformRestore(Zone z) {}
        public virtual void PerformRestore() {}

		public virtual void Reconnect(DockingManager dm)
		{
			if (mchild != null)
				mchild.Reconnect(dm);
		}

		public virtual void SaveToXml(XmlTextWriter xmlOut)
		{
			xmlOut.WriteAttributeString("Type", this.GetType().ToString());

			SaveInternalToXml(xmlOut);

			xmlOut.WriteStartElement("Child");

			if (mchild == null)
				xmlOut.WriteAttributeString("Type", "null");
			else
				mchild.SaveToXml(xmlOut);

			xmlOut.WriteEndElement();
		}

		public virtual void LoadFromXml(XmlTextReader xmlIn, int formatVersion)
		{
			LoadInternalFromXml(xmlIn, formatVersion);

			if (!xmlIn.Read())
				throw new ArgumentException(ResourceLibrary.GetString(WindowsControlsResourceKeys.InaccessibleNode, WindowsControlsResourceKeys.Root));

			if (xmlIn.Name != "Child")
				throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, ResourceLibrary.GetString(WindowsControlsResourceKeys.NodeNotFound, WindowsControlsResourceKeys.Root), "Child"));

			string type = xmlIn.GetAttribute(0);
			
			if (type != "null")
				mchild = CreateFromXml(xmlIn, false, formatVersion);

			if (!xmlIn.Read())
				throw new ArgumentException("");
		
			if (xmlIn.NodeType != XmlNodeType.EndElement)
				throw new ArgumentException(ResourceLibrary.GetString(WindowsControlsResourceKeys.FinalElementNotFound, WindowsControlsResourceKeys.Root));
		}

		public virtual void SaveInternalToXml(XmlTextWriter xmlOut) {}
		public virtual void LoadInternalFromXml(XmlTextReader xmlIn, int formatVersion) {}

		#endregion

		#region Methods

		[SecurityPermission(SecurityAction.Demand)]
		public static Restore CreateFromXml(XmlTextReader xmlIn, bool readIn, int formatVersion)
		{
			if (readIn)
			{
				if (!xmlIn.Read())
					throw new ArgumentException(ResourceLibrary.GetString(WindowsControlsResourceKeys.InaccessibleNode, WindowsControlsResourceKeys.Root));
			}
			
			string attrType = xmlIn.GetAttribute(0);

			Type newType = Type.GetType(attrType);

			Restore newRestore = newType.Assembly.CreateInstance(attrType, true, BindingFlags.Default, null, null, CultureInfo.CurrentCulture, null) as Restore;

			newRestore.LoadFromXml(xmlIn, formatVersion);

			return newRestore;
		}

		#endregion

		#region Properties

		public Restore Child
		{
			get { return mchild; }
			set { mchild = value; }
		}

		#endregion
	}

	public class RestoreContent : Restore
	{
		protected String mtitle;
		protected Content mcontent;

		#region Constructors

		public RestoreContent(): base()
		{
			mtitle = "";
			mcontent = null;
		}

		public RestoreContent(Content content)	: base()
		{
			mtitle = content.Title;
			mcontent = content;
		}

		public RestoreContent(Restore child, Content content): base(child)
		{
			mtitle = content.Title;
			mcontent = content;
		}

		#endregion

		#region Overrides

		public override void Reconnect(DockingManager dm)
		{
			mcontent = dm.Contents[mtitle];
			base.Reconnect(dm);
		}

		public override void SaveInternalToXml(XmlTextWriter xmlOut)
		{
			base.SaveInternalToXml(xmlOut);
			xmlOut.WriteStartElement("Content");
			xmlOut.WriteAttributeString("Name", mcontent.Title);
			xmlOut.WriteEndElement();				
		}

		public override void LoadInternalFromXml(XmlTextReader xmlIn, int formatVersion)
		{
			base.LoadInternalFromXml(xmlIn, formatVersion);

			if (!xmlIn.Read())
				throw new ArgumentException(ResourceLibrary.GetString(WindowsControlsResourceKeys.InaccessibleNode, WindowsControlsResourceKeys.Root));

			if (xmlIn.Name != "Content")
				throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, ResourceLibrary.GetString(WindowsControlsResourceKeys.NodeNotFound, WindowsControlsResourceKeys.Root), "Content"));

			mtitle = xmlIn.GetAttribute(0);
		}

		#endregion
	}
	
	public class RestoreContentState : RestoreContent
	{
		protected State mstate;

		#region Constructors

		public RestoreContentState(): base()
		{
		}

		public RestoreContentState(State state, Content content): base(content)
		{
			mstate = state;
		}

		public RestoreContentState(Restore child, State state, Content content)	: base(child, content)
		{
			mstate = state;
		}

		#endregion

		#region Overrides

		public override void PerformRestore(DockingManager dm)
		{
			dm.AddContentWithState(mcontent, mstate);				
		}

		public override void SaveInternalToXml(XmlTextWriter xmlOut)
		{
			base.SaveInternalToXml(xmlOut);
			xmlOut.WriteStartElement("State");
			xmlOut.WriteAttributeString("Value", mstate.ToString(CultureInfo.CurrentCulture));
			xmlOut.WriteEndElement();				
		}

		public override void LoadInternalFromXml(XmlTextReader xmlIn, int formatVersion)
		{
			base.LoadInternalFromXml(xmlIn, formatVersion);

			if (!xmlIn.Read())
				throw new ArgumentException(ResourceLibrary.GetString(WindowsControlsResourceKeys.InaccessibleNode, WindowsControlsResourceKeys.Root));

			if (xmlIn.Name != "State")
				throw new ArgumentException(ResourceLibrary.GetString(WindowsControlsResourceKeys.NodeNotFound, WindowsControlsResourceKeys.Root), "State");

			string attrState = xmlIn.GetAttribute(0);

			mstate = (State)Enum.Parse(typeof(State), attrState);
		}

		#endregion
	}
	
	public class RestoreAutoHideState : RestoreContentState
	{
		#region Constructors

		public RestoreAutoHideState() : base()
	    {
	    }
        
        public RestoreAutoHideState(State state, Content content)  : base(state, content)
        {
        }

        public RestoreAutoHideState(Restore child, State state, Content content) : base(child, state, content)
        {
        }

		#endregion
    
		#region Overrides

		public override void PerformRestore(DockingManager dm)
        {
            ContentCollection cc = new ContentCollection();
            cc.Add(mcontent);
            dm.AutoHideContents(cc, mstate);
        }

		#endregion
    }

    public class RestoreAutoHideAffinity : RestoreAutoHideState
    {
        protected StringCollection mnext;
        protected StringCollection mprevious;
        protected StringCollection mnextAll;
        protected StringCollection mpreviousAll;

		#region Constructors

		public RestoreAutoHideAffinity()
            : base()
        {
            mnext = new StringCollection();
            mprevious = new StringCollection();
            mnextAll = new StringCollection();
            mpreviousAll = new StringCollection();
        }

        public RestoreAutoHideAffinity(Restore child, 
                                       State state,
                                       Content content, 
                                       StringCollection nex,
                                       StringCollection previous,
                                       StringCollection nextAll,
                                       StringCollection previousAll)
        : base(child, state, content)
        {
            mnext = nex;				
            mprevious = previous;	
            mnextAll = nextAll;				
            mpreviousAll = previousAll;	
        }

		#endregion

		#region Overrides

        public override void PerformRestore(DockingManager dm)
        {   
            AutoHidePanel ahp = dm.AutoHidePanelForState(mstate);
            
            ahp.AddContent(mcontent, mnext, mprevious, mnextAll, mpreviousAll);
        }

        public override void SaveInternalToXml(XmlTextWriter xmlOut)
        {
            base.SaveInternalToXml(xmlOut);
            mnext.SaveToXml("Next", xmlOut);
            mprevious.SaveToXml("Previous", xmlOut);
            mnextAll.SaveToXml("NextAll", xmlOut);
            mpreviousAll.SaveToXml("PreviousAll", xmlOut);
        }

        public override void LoadInternalFromXml(XmlTextReader xmlIn, int formatVersion)
        {
            base.LoadInternalFromXml(xmlIn, formatVersion);
            mnext.LoadFromXml("Next", xmlIn);
            mprevious.LoadFromXml("Previous", xmlIn);
            mnextAll.LoadFromXml("NextAll", xmlIn);
            mpreviousAll.LoadFromXml("PreviousAll", xmlIn);
        }

		#endregion
    }

	public class RestoreContentDockingAffinity : RestoreContentState
	{
		protected Size msize;
		protected Point mlocation;
		protected StringCollection mbest;
		protected StringCollection mnext;
		protected StringCollection mprevious;
		protected StringCollection mnextAll;
		protected StringCollection mpreviousAll;

		#region Constructors

		public RestoreContentDockingAffinity()
			: base()
		{
			mbest = new StringCollection();
			mnext = new StringCollection();
			mprevious = new StringCollection();
			mnextAll = new StringCollection();
			mpreviousAll = new StringCollection();
		}

		public RestoreContentDockingAffinity(Restore child, 
										     State state, 
											 Content content, 
											 StringCollection best,
											 StringCollection nex,
											 StringCollection previous,
											 StringCollection nextAll,
											 StringCollection previousAll)
			: base(child, state, content)
		{
			mbest = best;
			mnext = nex;
			mprevious = previous;
			mnextAll = nextAll;
			mpreviousAll = previousAll;
			msize = content.DisplaySize;
			mlocation = content.DisplayLocation;
		}

		#endregion

		#region Overrides
		
		public override void PerformRestore(DockingManager dm)
		{
			int count = dm.Container.Controls.Count;

			int min = -1;
			int max = count;

			if (dm.InnerControl != null)
				min = dm.Container.Controls.IndexOf(dm.InnerControl);

			if (dm.OuterControl != null)
				max = dm.OuterControlIndex();

			int beforeIndex = -1;
			int afterIndex = max;
			int beforeAllIndex = -1;
			int afterAllIndex = max;

			for(int index=0; index<count; index++)
			{
				Zone z = dm.Container.Controls[index] as Zone;

				if (z != null)
				{
					StringCollection sc = ZoneHelper.ContentNames(z);
					
					if (mstate == z.State)
					{
						if (sc.Contains(mbest))
						{
							if (mchild != null)
								mchild.PerformRestore(z);
							else
							{
								dm.AddContentToZone(mcontent, z, 0);
							}
							return;
						}

						if (sc.Contains(mprevious))
						{
							if (index > beforeIndex)
								beforeIndex = index;
						}
						
						if (sc.Contains(mnext))
						{
							if (index < afterIndex)
								afterIndex = index;
						}
					}
					else
					{
						if (sc.Contains(mpreviousAll))
						{
							if (index > beforeAllIndex)
								beforeAllIndex = index;
						}
						
						if (sc.Contains(mnextAll))
						{
							if (index < afterAllIndex)
								afterAllIndex = index;
						}
					}
				}
			}

			dm.Container.SuspendLayout();

			Zone newZ = dm.CreateZoneForContent(mstate);

			mcontent.DisplaySize = msize;
			mcontent.DisplayLocation = mlocation;

			dm.AddContentToZone(mcontent, newZ, 0);

			if (beforeIndex != -1)
			{
				if (beforeAllIndex > beforeIndex)
					beforeIndex = beforeAllIndex;

				if (beforeIndex >= max)
					beforeIndex = max - 1;

				dm.Container.Controls.SetChildIndex(newZ, beforeIndex + 1);
			}
			else
			{
				if (afterAllIndex < afterIndex)
					afterIndex = afterAllIndex;

				if (afterIndex <= min)
					afterIndex = min + 1;
				
				if (afterIndex > min)
					dm.Container.Controls.SetChildIndex(newZ, afterIndex);
				else
				{
					dm.ReorderZoneToInnerMost(newZ);
				}
			}

			dm.Container.ResumeLayout();
		}

		public override void SaveInternalToXml(XmlTextWriter xmlOut)
		{
			base.SaveInternalToXml(xmlOut);
			xmlOut.WriteStartElement("Position");
			xmlOut.WriteAttributeString("Size", DrawHelpers.SizeToString(msize));
			xmlOut.WriteAttributeString("Location", DrawHelpers.PointToString(mlocation));
			xmlOut.WriteEndElement();				
			mbest.SaveToXml("Best", xmlOut);
			mnext.SaveToXml("Next", xmlOut);
			mprevious.SaveToXml("Previous", xmlOut);
			mnextAll.SaveToXml("NextAll", xmlOut);
			mpreviousAll.SaveToXml("PreviousAll", xmlOut);
		}

		public override void LoadInternalFromXml(XmlTextReader xmlIn, int formatVersion)
		{
			base.LoadInternalFromXml(xmlIn, formatVersion);

			if (!xmlIn.Read())
				throw new ArgumentException(ResourceLibrary.GetString(WindowsControlsResourceKeys.InaccessibleNode, WindowsControlsResourceKeys.Root));

			if (xmlIn.Name != "Position")
				throw new ArgumentException(ResourceLibrary.GetString(WindowsControlsResourceKeys.NodeNotFound, WindowsControlsResourceKeys.Root), "Position");

			string attrSize = xmlIn.GetAttribute(0);
			string attrLocation = xmlIn.GetAttribute(1);

			msize = DrawHelpers.StringToSize(attrSize);
			mlocation = DrawHelpers.StringToPoint(attrLocation);

			mbest.LoadFromXml("Best", xmlIn);
			mnext.LoadFromXml("Next", xmlIn);
			mprevious.LoadFromXml("Previous", xmlIn);
			mnextAll.LoadFromXml("NextAll", xmlIn);
			mpreviousAll.LoadFromXml("PreviousAll", xmlIn);
		}

		#endregion
	}

	public class RestoreContentFloatingAffinity : RestoreContentState
	{
		protected Size msize;
		protected Point mlocation;
		protected StringCollection mbest;
		protected StringCollection massociates;

		#region Constructors

		public RestoreContentFloatingAffinity()
			: base()
		{
			mbest = new StringCollection();
			massociates = new StringCollection();
		}

		public RestoreContentFloatingAffinity(Restore child, 
										      State state, 
											  Content content, 
											  StringCollection best,
											  StringCollection associates)
			: base(child, state, content)
		{
			mbest = best;
			massociates = associates;
			msize = content.DisplaySize;
			mlocation = content.DisplayLocation;

			if (mbest.Contains(content.Title))
				mbest.Remove(content.Title);

			if (massociates.Contains(content.Title))
				massociates.Remove(content.Title);
		}

		#endregion

		#region Overrides

		public override void PerformRestore(DockingManager dm)
		{
			Form[] owned = dm.Container.FindForm().OwnedForms;

			FloatingForm target = null;

			foreach(Form f in owned)
			{
				FloatingForm ff = f as FloatingForm;

				if (ff != null)
				{
					if (ZoneHelper.ContentNames(ff.Zone).Contains(mbest))
					{
						target = ff;
						break;
					}
				}
			}

			if (target == null)
			{
				foreach(Form f in owned)
				{
					FloatingForm ff = f as FloatingForm;

					if (ff != null)
					{
						if (ZoneHelper.ContentNames(ff.Zone).Contains(massociates))
						{
							target = ff;
							break;
						}
					}
				}
			}

			if (target != null)
			{
				mchild.PerformRestore(target.Zone);
			}
			else
			{
				mcontent.DisplayLocation = mlocation;
				mcontent.DisplaySize = msize;

				dm.AddContentWithState(mcontent, State.Floating);
			}
		}

		public override void SaveInternalToXml(XmlTextWriter xmlOut)
		{
			base.SaveInternalToXml(xmlOut);
			xmlOut.WriteStartElement("Position");
			xmlOut.WriteAttributeString("Size", DrawHelpers.SizeToString(msize));
			xmlOut.WriteAttributeString("Location", DrawHelpers.PointToString(mlocation));
			xmlOut.WriteEndElement();				
			mbest.SaveToXml("Best", xmlOut);
			massociates.SaveToXml("Associates", xmlOut);
		}

		public override void LoadInternalFromXml(XmlTextReader xmlIn, int formatVersion)
		{
			base.LoadInternalFromXml(xmlIn, formatVersion);

			if (!xmlIn.Read())
				throw new ArgumentException(ResourceLibrary.GetString(WindowsControlsResourceKeys.InaccessibleNode, WindowsControlsResourceKeys.Root));

			if (xmlIn.Name != "Position")
				throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, ResourceLibrary.GetString(WindowsControlsResourceKeys.NodeNotFound, WindowsControlsResourceKeys.Root), "Position"));

			string attrSize = xmlIn.GetAttribute(0);
			string attrLocation = xmlIn.GetAttribute(1);

			msize = DrawHelpers.StringToSize(attrSize);
			mlocation = DrawHelpers.StringToPoint(attrLocation);

			mbest.LoadFromXml("Best", xmlIn);
			massociates.LoadFromXml("Associates", xmlIn);
		}

		#endregion
	}

	public class RestoreZoneAffinity : RestoreContent
	{
		protected Decimal mspace;
		protected StringCollection mbest;
		protected StringCollection mnext;
		protected StringCollection mprevious;

		#region Constructors

		public RestoreZoneAffinity()
			: base()
		{
			mspace = 50m;

			mbest = new StringCollection();
			mnext = new StringCollection();
			mprevious = new StringCollection();
		}

		public RestoreZoneAffinity(Restore child, 
								   Content content, 
								   StringCollection best,
								   StringCollection nex,
								   StringCollection previous)
			: base(child, content)
		{
			mbest = best;				
			mnext = nex;				
			mprevious = previous;	
			
			if (content.Visible)			
				mspace = content.ParentWindowContent.ZoneArea;
			else
				mspace = 50m;
		}

		#endregion

		#region Overrides

		public override void PerformRestore(Zone z)
		{
			int count = z.Windows.Count;
			int beforeIndex = - 1;
			int afterIndex = count;
		
			for(int index=0; index<count; index++)
			{
				WindowContent wc = z.Windows[index] as WindowContent;

				if (wc != null)
				{
					if (wc.Contents.Contains(mbest))
					{
						if (mchild == null)
						{
							wc.Contents.Add(mcontent);
						}
						else
						{
							mchild.PerformRestore(wc);
						}

						return;
					}

					if (wc.Contents.Contains(mprevious))
					{
						if (index > beforeIndex)
							beforeIndex = index;
					}
					
					if (wc.Contents.Contains(mnext))
					{
						if (index < afterIndex)
							afterIndex = index;
					}
				}
			}

			Window newW =  z.DockingManager.CreateWindowForContent(mcontent);

			ZoneSequence zs = z as ZoneSequence;

			if (zs != null)
			{
				zs.SuppressReposition();
			}

			if (beforeIndex >= 0)
			{
				z.Windows.Insert(beforeIndex + 1, newW);
			}
			else
			{
				z.Windows.Insert(afterIndex, newW);
			}

			if (zs != null)
			{
				zs.ModifyWindowSpace(newW, mspace);
			}
		}

		public override void SaveInternalToXml(XmlTextWriter xmlOut)
		{
			base.SaveInternalToXml(xmlOut);
			xmlOut.WriteStartElement("Space");
			xmlOut.WriteAttributeString("Value", mspace.ToString(CultureInfo.CurrentCulture));
			xmlOut.WriteEndElement();				
			mbest.SaveToXml("Best", xmlOut);
			mnext.SaveToXml("Next", xmlOut);
			mprevious.SaveToXml("Previous", xmlOut);
		}

		public override void LoadInternalFromXml(XmlTextReader xmlIn, int formatVersion)
		{
			base.LoadInternalFromXml(xmlIn, formatVersion);

			if (!xmlIn.Read())
				throw new ArgumentException(ResourceLibrary.GetString(WindowsControlsResourceKeys.InaccessibleNode, WindowsControlsResourceKeys.Root));

			if (xmlIn.Name != "Space")
				throw new ArgumentException((String.Format(CultureInfo.CurrentCulture, ResourceLibrary.GetString(WindowsControlsResourceKeys.NodeNotFound, WindowsControlsResourceKeys.Root), "Space")));

			string attrSpace = xmlIn.GetAttribute(0);

			mspace = Decimal.Parse(attrSpace, CultureInfo.CurrentCulture);

			mbest.LoadFromXml("Best", xmlIn);
			mnext.LoadFromXml("Next", xmlIn);
			mprevious.LoadFromXml("Previous", xmlIn);
		}

		#endregion
	}

	public class RestoreWindowContent : RestoreContent
	{
		protected bool mselected;
		protected StringCollection mnext;
		protected StringCollection mprevious;

		#region Constructors

		public RestoreWindowContent()
			: base()
		{
			mselected = false;
			mnext = new StringCollection();
			mprevious = new StringCollection();
		}

		public RestoreWindowContent(Restore child, 
									Content content, 
									StringCollection nex, 
									StringCollection previous,
									bool selected)
			: base(child, content)
		{
            mselected = selected;
            mnext = nex;
			mprevious = previous;
		}

		#endregion

		#region Overrides

		public override void PerformRestore(Window w)
		{
			WindowContent wc = w as WindowContent;

			int bestIndex = -1;

			foreach(String s in mprevious)
			{
				if (wc.Contents.Contains(s))
				{
					int previousIndex = wc.Contents.IndexOf(wc.Contents[s]);

					if (previousIndex > bestIndex)
						bestIndex = previousIndex;
				}
			}

			if (bestIndex >= 0)
			{
				wc.Contents.Insert(bestIndex + 1, mcontent);
			}
			else
			{
				bestIndex = wc.Contents.Count;

				foreach(String s in mnext)
				{
					if (wc.Contents.Contains(s))
					{
						int nextIndex = wc.Contents.IndexOf(wc.Contents[s]);

						if (nextIndex < bestIndex)
							bestIndex = nextIndex;
					}
				}

				wc.Contents.Insert(bestIndex, mcontent);
			}
			
			if (mselected)
			    mcontent.BringToFront();
		}

		public override void SaveInternalToXml(XmlTextWriter xmlOut)
		{
			base.SaveInternalToXml(xmlOut);
			mnext.SaveToXml("Next", xmlOut);
			mprevious.SaveToXml("Previous", xmlOut);
        
            xmlOut.WriteStartElement("Selected");
            xmlOut.WriteAttributeString("Value", mselected.ToString(CultureInfo.CurrentCulture));
            xmlOut.WriteEndElement();				
        }

		public override void LoadInternalFromXml(XmlTextReader xmlIn, int formatVersion)
		{
			base.LoadInternalFromXml(xmlIn, formatVersion);
			mnext.LoadFromXml("Next", xmlIn);
			mprevious.LoadFromXml("Previous", xmlIn);
        
            if (formatVersion >= 4)
            {
                if (!xmlIn.Read())
                    throw new ArgumentException(ResourceLibrary.GetString(WindowsControlsResourceKeys.InaccessibleNode, WindowsControlsResourceKeys.Root));

                if (xmlIn.Name != "Selected")
                    throw new ArgumentException((String.Format(CultureInfo.CurrentCulture, ResourceLibrary.GetString(WindowsControlsResourceKeys.NodeNotFound, WindowsControlsResourceKeys.Root), "Selected")));

                mselected = Convert.ToBoolean(xmlIn.GetAttribute(0), CultureInfo.CurrentCulture);
            }
        }

		#endregion
	}
}
